# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: site-packages\dateutil\parser.py
"""
This module offers a generic date/time string parser which is able to parse
most known formats to represent a date and/or time.

This module attempts to be forgiving with regards to unlikely input formats,
returning a datetime object even for dates which are ambiguous. If an element
of a date/time stamp is omitted, the following rules are applied:
- If AM or PM is left unspecified, a 24-hour clock is assumed, however, an hour
  on a 12-hour clock (``0 <= hour <= 12``) *must* be specified if AM or PM is
  specified.
- If a time zone is omitted, a timezone-naive datetime is returned.

If any other elements are missing, they are taken from the
:class:`datetime.datetime` object passed to the parameter ``default``. If this
results in a day number exceeding the valid number of days per month, the
value falls back to the end of the month.

Additional resources about date/time string formats can be found below:

- `A summary of the international standard date and time notation
  <http://www.cl.cam.ac.uk/~mgk25/iso-time.html>`_
- `W3C Date and Time Formats <http://www.w3.org/TR/NOTE-datetime>`_
- `Time Formats (Planetary Rings Node) <http://pds-rings.seti.org/tools/time_formats.html>`_
- `CPAN ParseDate module
  <http://search.cpan.org/~muir/Time-modules-2013.0912/lib/Time/ParseDate.pm>`_
- `Java SimpleDateFormat Class
  <https://docs.oracle.com/javase/6/docs/api/java/text/SimpleDateFormat.html>`_
"""
from __future__ import unicode_literals
import datetime, string, time, collections, re
from io import StringIO
from calendar import monthrange
from six import text_type, binary_type, integer_types
from . import relativedelta
from . import tz
__all__ = [
 'parse', 'parserinfo']

class _timelex(object):
    _split_decimal = re.compile('([.,])')

    def __init__(self, instream):
        if isinstance(instream, binary_type):
            instream = instream.decode()
        if isinstance(instream, text_type):
            instream = StringIO(instream)
        if getattr(instream, 'read', None) is None:
            raise TypeError(('Parser must be a string or character stream, not {itype}').format(itype=instream.__class__.__name__))
        self.instream = instream
        self.charstack = []
        self.tokenstack = []
        self.eof = False

    def get_token--- This code section failed: ---

  82       0  LOAD_FAST                'self'
           2  LOAD_ATTR                'tokenstack'
           4  POP_JUMP_IF_FALSE    18  'to 18'

  83       6  LOAD_FAST                'self'
           8  LOAD_ATTR                'tokenstack'
          10  LOAD_ATTR                'pop'
          12  LOAD_CONST            0  0
          14  CALL_FUNCTION_1       1  ''
          16  RETURN_END_IF    

  85      18  LOAD_CONST            0  False
          20  STORE_FAST               'seenletters'

  86      22  LOAD_CONST               None
          24  STORE_FAST               'token'

  87      26  LOAD_CONST               None
          28  STORE_FAST               'state'

  89      30  SETUP_LOOP          544  'to 544'
          34  LOAD_FAST                'self'
          36  LOAD_ATTR                'eof'
          38  POP_JUMP_IF_TRUE    542  'to 542'

  94      42  LOAD_FAST                'self'
          44  LOAD_ATTR                'charstack'
          46  POP_JUMP_IF_FALSE    62  'to 62'

  95      48  LOAD_FAST                'self'
          50  LOAD_ATTR                'charstack'
          52  LOAD_ATTR                'pop'
          54  LOAD_CONST            0  0
          56  CALL_FUNCTION_1       1  ''
          58  STORE_FAST               'nextchar'
          60  JUMP_FORWARD        100  'to 100'
          62  ELSE                     '100'

  97      62  LOAD_FAST                'self'
          64  LOAD_ATTR                'instream'
          66  LOAD_ATTR                'read'
          68  LOAD_CONST            1  1
          70  CALL_FUNCTION_1       1  ''
          72  STORE_FAST               'nextchar'

  98      74  SETUP_LOOP          100  'to 100'
          76  LOAD_FAST                'nextchar'
          78  LOAD_CONST               '\x00'
          80  COMPARE_OP               '=='
          82  POP_JUMP_IF_FALSE    98  'to 98'

  99      84  LOAD_FAST                'self'
          86  LOAD_ATTR                'instream'
          88  LOAD_ATTR                'read'
          90  LOAD_CONST            1  1
          92  CALL_FUNCTION_1       1  ''
          94  STORE_FAST               'nextchar'
          96  JUMP_BACK            76  'to 76'
          98  POP_BLOCK        
       100_0  COME_FROM_LOOP       74  '74'
       100_1  COME_FROM            60  '60'

 101     100  LOAD_FAST                'nextchar'
         102  POP_JUMP_IF_TRUE    114  'to 114'

 102     104  LOAD_CONST            1  True
         106  LOAD_FAST                'self'
         108  STORE_ATTR               'eof'

 103     110  BREAK_LOOP       
         112  JUMP_BACK            34  'to 34'
         114  ELSE                     '540'

 104     114  LOAD_FAST                'state'
         116  POP_JUMP_IF_TRUE    176  'to 176'

 107     118  LOAD_FAST                'nextchar'
         120  STORE_FAST               'token'

 108     122  LOAD_FAST                'self'
         124  LOAD_ATTR                'isword'
         126  LOAD_FAST                'nextchar'
         128  CALL_FUNCTION_1       1  ''
         130  POP_JUMP_IF_FALSE   138  'to 138'

 109     132  LOAD_CONST               'a'
         134  STORE_FAST               'state'
         136  JUMP_FORWARD        174  'to 174'
         138  ELSE                     '174'

 110     138  LOAD_FAST                'self'
         140  LOAD_ATTR                'isnum'
         142  LOAD_FAST                'nextchar'
         144  CALL_FUNCTION_1       1  ''
         146  POP_JUMP_IF_FALSE   154  'to 154'

 111     148  LOAD_CONST               '0'
         150  STORE_FAST               'state'
         152  JUMP_FORWARD        174  'to 174'
         154  ELSE                     '174'

 112     154  LOAD_FAST                'self'
         156  LOAD_ATTR                'isspace'
         158  LOAD_FAST                'nextchar'
         160  CALL_FUNCTION_1       1  ''
         162  POP_JUMP_IF_FALSE   172  'to 172'

 113     164  LOAD_CONST               ' '
         166  STORE_FAST               'token'

 114     168  BREAK_LOOP       
         170  JUMP_FORWARD        174  'to 174'
         172  ELSE                     '174'

 116     172  BREAK_LOOP       
       174_0  COME_FROM           170  '170'
       174_1  COME_FROM           152  '152'
       174_2  COME_FROM           136  '136'
         174  JUMP_BACK            34  'to 34'
         176  ELSE                     '540'

 117     176  LOAD_FAST                'state'
         178  LOAD_CONST               'a'
         180  COMPARE_OP               '=='
         182  POP_JUMP_IF_FALSE   248  'to 248'

 120     186  LOAD_CONST            1  True
         188  STORE_FAST               'seenletters'

 121     190  LOAD_FAST                'self'
         192  LOAD_ATTR                'isword'
         194  LOAD_FAST                'nextchar'
         196  CALL_FUNCTION_1       1  ''
         198  POP_JUMP_IF_FALSE   210  'to 210'

 122     200  LOAD_FAST                'token'
         202  LOAD_FAST                'nextchar'
         204  INPLACE_ADD      
         206  STORE_FAST               'token'
         208  JUMP_FORWARD        246  'to 246'
         210  ELSE                     '246'

 123     210  LOAD_FAST                'nextchar'
         212  LOAD_CONST               '.'
         214  COMPARE_OP               '=='
         216  POP_JUMP_IF_FALSE   232  'to 232'

 124     218  LOAD_FAST                'token'
         220  LOAD_FAST                'nextchar'
         222  INPLACE_ADD      
         224  STORE_FAST               'token'

 125     226  LOAD_CONST               'a.'
         228  STORE_FAST               'state'
         230  JUMP_FORWARD        246  'to 246'
         232  ELSE                     '246'

 127     232  LOAD_FAST                'self'
         234  LOAD_ATTR                'charstack'
         236  LOAD_ATTR                'append'
         238  LOAD_FAST                'nextchar'
         240  CALL_FUNCTION_1       1  ''
         242  POP_TOP          

 128     244  BREAK_LOOP       
       246_0  COME_FROM           230  '230'
       246_1  COME_FROM           208  '208'
         246  JUMP_BACK            34  'to 34'
         248  ELSE                     '540'

 129     248  LOAD_FAST                'state'
         250  LOAD_CONST               '0'
         252  COMPARE_OP               '=='
         254  POP_JUMP_IF_FALSE   344  'to 344'

 132     258  LOAD_FAST                'self'
         260  LOAD_ATTR                'isnum'
         262  LOAD_FAST                'nextchar'
         264  CALL_FUNCTION_1       1  ''
         266  POP_JUMP_IF_FALSE   280  'to 280'

 133     270  LOAD_FAST                'token'
         272  LOAD_FAST                'nextchar'
         274  INPLACE_ADD      
         276  STORE_FAST               'token'
         278  JUMP_FORWARD        342  'to 342'
         280  ELSE                     '342'

 134     280  LOAD_FAST                'nextchar'
         282  LOAD_CONST               '.'
         284  COMPARE_OP               '=='
         286  POP_JUMP_IF_TRUE    314  'to 314'
         290  LOAD_FAST                'nextchar'
         292  LOAD_CONST               ','
         294  COMPARE_OP               '=='
         296  POP_JUMP_IF_FALSE   328  'to 328'
         300  LOAD_GLOBAL              'len'
         302  LOAD_FAST                'token'
         304  CALL_FUNCTION_1       1  ''
         306  LOAD_CONST            2  2
         308  COMPARE_OP               '>='
       310_0  COME_FROM           296  '296'
       310_1  COME_FROM           286  '286'
         310  POP_JUMP_IF_FALSE   328  'to 328'

 135     314  LOAD_FAST                'token'
         316  LOAD_FAST                'nextchar'
         318  INPLACE_ADD      
         320  STORE_FAST               'token'

 136     322  LOAD_CONST               '0.'
         324  STORE_FAST               'state'
         326  JUMP_FORWARD        342  'to 342'
         328  ELSE                     '342'

 138     328  LOAD_FAST                'self'
         330  LOAD_ATTR                'charstack'
         332  LOAD_ATTR                'append'
         334  LOAD_FAST                'nextchar'
         336  CALL_FUNCTION_1       1  ''
         338  POP_TOP          

 139     340  BREAK_LOOP       
       342_0  COME_FROM           326  '326'
       342_1  COME_FROM           278  '278'
         342  JUMP_BACK            34  'to 34'
         344  ELSE                     '540'

 140     344  LOAD_FAST                'state'
         346  LOAD_CONST               'a.'
         348  COMPARE_OP               '=='
         350  POP_JUMP_IF_FALSE   446  'to 446'

 143     354  LOAD_CONST            1  True
         356  STORE_FAST               'seenletters'

 144     358  LOAD_FAST                'nextchar'
         360  LOAD_CONST               '.'
         362  COMPARE_OP               '=='
         364  POP_JUMP_IF_TRUE    380  'to 380'
         368  LOAD_FAST                'self'
         370  LOAD_ATTR                'isword'
         372  LOAD_FAST                'nextchar'
         374  CALL_FUNCTION_1       1  ''
       376_0  COME_FROM           364  '364'
         376  POP_JUMP_IF_FALSE   390  'to 390'

 145     380  LOAD_FAST                'token'
         382  LOAD_FAST                'nextchar'
         384  INPLACE_ADD      
         386  STORE_FAST               'token'
         388  JUMP_FORWARD        444  'to 444'
         390  ELSE                     '444'

 146     390  LOAD_FAST                'self'
         392  LOAD_ATTR                'isnum'
         394  LOAD_FAST                'nextchar'
         396  CALL_FUNCTION_1       1  ''
         398  POP_JUMP_IF_FALSE   430  'to 430'
         402  LOAD_FAST                'token'
         404  LOAD_CONST           -1  -1
         406  BINARY_SUBSCR    
         408  LOAD_CONST               '.'
         410  COMPARE_OP               '=='
         412  POP_JUMP_IF_FALSE   430  'to 430'

 147     416  LOAD_FAST                'token'
         418  LOAD_FAST                'nextchar'
         420  INPLACE_ADD      
         422  STORE_FAST               'token'

 148     424  LOAD_CONST               '0.'
         426  STORE_FAST               'state'
         428  JUMP_FORWARD        444  'to 444'
       430_0  COME_FROM           412  '412'

 150     430  LOAD_FAST                'self'
         432  LOAD_ATTR                'charstack'
         434  LOAD_ATTR                'append'
         436  LOAD_FAST                'nextchar'
         438  CALL_FUNCTION_1       1  ''
         440  POP_TOP          

 151     442  BREAK_LOOP       
       444_0  COME_FROM           428  '428'
       444_1  COME_FROM           388  '388'
         444  JUMP_BACK            34  'to 34'
         446  ELSE                     '540'

 152     446  LOAD_FAST                'state'
         448  LOAD_CONST               '0.'
         450  COMPARE_OP               '=='
         452  POP_JUMP_IF_FALSE    34  'to 34'

 155     454  LOAD_FAST                'nextchar'
         456  LOAD_CONST               '.'
         458  COMPARE_OP               '=='
         460  POP_JUMP_IF_TRUE    476  'to 476'
         464  LOAD_FAST                'self'
         466  LOAD_ATTR                'isnum'
         468  LOAD_FAST                'nextchar'
         470  CALL_FUNCTION_1       1  ''
       472_0  COME_FROM           460  '460'
         472  POP_JUMP_IF_FALSE   486  'to 486'

 156     476  LOAD_FAST                'token'
         478  LOAD_FAST                'nextchar'
         480  INPLACE_ADD      
         482  STORE_FAST               'token'
         484  JUMP_BACK            34  'to 34'
         486  ELSE                     '540'

 157     486  LOAD_FAST                'self'
         488  LOAD_ATTR                'isword'
         490  LOAD_FAST                'nextchar'
         492  CALL_FUNCTION_1       1  ''
         494  POP_JUMP_IF_FALSE   526  'to 526'
         498  LOAD_FAST                'token'
         500  LOAD_CONST           -1  -1
         502  BINARY_SUBSCR    
         504  LOAD_CONST               '.'
         506  COMPARE_OP               '=='
         508  POP_JUMP_IF_FALSE   526  'to 526'

 158     512  LOAD_FAST                'token'
         514  LOAD_FAST                'nextchar'
         516  INPLACE_ADD      
         518  STORE_FAST               'token'

 159     520  LOAD_CONST               'a.'
         522  STORE_FAST               'state'
         524  JUMP_BACK            34  'to 34'
       526_0  COME_FROM           508  '508'

 161     526  LOAD_FAST                'self'
         528  LOAD_ATTR                'charstack'
         530  LOAD_ATTR                'append'
         532  LOAD_FAST                'nextchar'
         534  CALL_FUNCTION_1       1  ''
         536  POP_TOP          

 162     538  BREAK_LOOP       
       540_0  COME_FROM           452  '452'
       540_1  COME_FROM            38  '38'
         540  JUMP_BACK            34  'to 34'
         542  POP_BLOCK        
       544_0  COME_FROM_LOOP       30  '30'

 164     544  LOAD_FAST                'state'
         546  LOAD_CONST               ('a.', '0.')
         548  COMPARE_OP               'in'
         550  POP_JUMP_IF_FALSE   652  'to 652'
         554  LOAD_FAST                'seenletters'
         556  POP_JUMP_IF_TRUE    590  'to 590'
         560  LOAD_FAST                'token'
         562  LOAD_ATTR                'count'
         564  LOAD_CONST               '.'
         566  CALL_FUNCTION_1       1  ''
         568  LOAD_CONST            1  1
         570  COMPARE_OP               '>'
         572  POP_JUMP_IF_TRUE    590  'to 590'

 165     576  LOAD_FAST                'token'
         578  LOAD_CONST           -1  -1
         580  BINARY_SUBSCR    
         582  LOAD_CONST               '.,'
         584  COMPARE_OP               'in'
       586_0  COME_FROM           572  '572'
       586_1  COME_FROM           556  '556'
         586  POP_JUMP_IF_FALSE   652  'to 652'

 166     590  LOAD_FAST                'self'
         592  LOAD_ATTR                '_split_decimal'
         594  LOAD_ATTR                'split'
         596  LOAD_FAST                'token'
         598  CALL_FUNCTION_1       1  ''
         600  STORE_FAST               'l'

 167     602  LOAD_FAST                'l'
         604  LOAD_CONST            0  0
         606  BINARY_SUBSCR    
         608  STORE_FAST               'token'

 168     610  SETUP_LOOP          652  'to 652'
         612  LOAD_FAST                'l'
         614  LOAD_CONST            1  1
         616  LOAD_CONST               None
         618  BUILD_SLICE_2         2  ''
         620  BINARY_SUBSCR    
         622  GET_ITER         
         624  FOR_ITER            650  'to 650'
         626  STORE_FAST               'tok'

 169     628  LOAD_FAST                'tok'
         630  POP_JUMP_IF_FALSE   624  'to 624'

 170     634  LOAD_FAST                'self'
         636  LOAD_ATTR                'tokenstack'
         638  LOAD_ATTR                'append'
         640  LOAD_FAST                'tok'
         642  CALL_FUNCTION_1       1  ''
         644  POP_TOP          
         646  JUMP_BACK           624  'to 624'
         650  POP_BLOCK        
       652_0  COME_FROM_LOOP      610  '610'
       652_1  COME_FROM           586  '586'
       652_2  COME_FROM           550  '550'

 172     652  LOAD_FAST                'state'
         654  LOAD_CONST               '0.'
         656  COMPARE_OP               '=='
         658  POP_JUMP_IF_FALSE   690  'to 690'
         662  LOAD_FAST                'token'
         664  LOAD_ATTR                'count'
         666  LOAD_CONST               '.'
         668  CALL_FUNCTION_1       1  ''
         670  LOAD_CONST            0  0
         672  COMPARE_OP               '=='
         674  POP_JUMP_IF_FALSE   690  'to 690'

 173     678  LOAD_FAST                'token'
         680  LOAD_ATTR                'replace'
         682  LOAD_CONST               ','
         684  LOAD_CONST               '.'
         686  CALL_FUNCTION_2       2  ''
         688  STORE_FAST               'token'
       690_0  COME_FROM           674  '674'
       690_1  COME_FROM           658  '658'

 175     690  LOAD_FAST                'token'
         692  RETURN_VALUE     
          -1  RETURN_LAST      

Parse error at or near `JUMP_BACK' instruction at offset 540

    def __iter__(self):
        return self

    def __next__(self):
        token = self.get_token()
        if token is None:
            raise StopIteration
        return token

    def next(self):
        return self.__next__()

    @classmethod
    def split(cls, s):
        return list(cls(s))

    @classmethod
    def isword(cls, nextchar):
        """ Whether or not the next character is part of a word """
        return nextchar.isalpha()

    @classmethod
    def isnum(cls, nextchar):
        """ Whether the next character is part of a number """
        return nextchar.isdigit()

    @classmethod
    def isspace(cls, nextchar):
        """ Whether the next character is whitespace """
        return nextchar.isspace()


class _resultbase(object):

    def __init__(self):
        for attr in self.__slots__:
            setattr(self, attr, None)

    def _repr(self, classname):
        l = []
        for attr in self.__slots__:
            value = getattr(self, attr)
            if value is not None:
                l.append('%s=%s' % (attr, repr(value)))

        return '%s(%s)' % (classname, (', ').join(l))

    def __len__(self):
        return sum((getattr(self, attr) is not None for attr in self.__slots__))

    def __repr__(self):
        return self._repr(self.__class__.__name__)


class parserinfo(object):
    """
    Class which handles what inputs are accepted. Subclass this to customize
    the language and acceptable values for each parameter.
    
    :param dayfirst:
            Whether to interpret the first value in an ambiguous 3-integer date
            (e.g. 01/05/09) as the day (``True``) or month (``False``). If
            ``yearfirst`` is set to ``True``, this distinguishes between YDM
            and YMD. Default is ``False``.
    
    :param yearfirst:
            Whether to interpret the first value in an ambiguous 3-integer date
            (e.g. 01/05/09) as the year. If ``True``, the first number is taken
            to be the year, otherwise the last number is taken to be the year.
            Default is ``False``.
    """
    JUMP = [
     ' ', '.', ',', ';', '-', '/', "'",
     'at', 'on', 'and', 'ad', 'm', 't', 'of',
     'st', 'nd', 'rd', 'th']
    WEEKDAYS = [
     ('Mon', 'Monday'),
     ('Tue', 'Tuesday'),
     ('Wed', 'Wednesday'),
     ('Thu', 'Thursday'),
     ('Fri', 'Friday'),
     ('Sat', 'Saturday'),
     ('Sun', 'Sunday')]
    MONTHS = [('Jan', 'January'),
     ('Feb', 'February'),
     ('Mar', 'March'),
     ('Apr', 'April'),
     ('May', 'May'),
     ('Jun', 'June'),
     ('Jul', 'July'),
     ('Aug', 'August'),
     ('Sep', 'Sept', 'September'),
     ('Oct', 'October'),
     ('Nov', 'November'),
     ('Dec', 'December')]
    HMS = [('h', 'hour', 'hours'),
     ('m', 'minute', 'minutes'),
     ('s', 'second', 'seconds')]
    AMPM = [('am', 'a'),
     ('pm', 'p')]
    UTCZONE = ['UTC', 'GMT', 'Z']
    PERTAIN = ['of']
    TZOFFSET = {}

    def __init__(self, dayfirst=False, yearfirst=False):
        self._jump = self._convert(self.JUMP)
        self._weekdays = self._convert(self.WEEKDAYS)
        self._months = self._convert(self.MONTHS)
        self._hms = self._convert(self.HMS)
        self._ampm = self._convert(self.AMPM)
        self._utczone = self._convert(self.UTCZONE)
        self._pertain = self._convert(self.PERTAIN)
        self.dayfirst = dayfirst
        self.yearfirst = yearfirst
        self._year = time.localtime().tm_year
        self._century = self._year // 100 * 100

    def _convert(self, lst):
        dct = {}
        for i, v in enumerate(lst):
            if isinstance(v, tuple):
                for v in v:
                    dct[v.lower()] = i

            else:
                dct[v.lower()] = i

        return dct

    def jump(self, name):
        return name.lower() in self._jump

    def weekday(self, name):
        if len(name) >= min((len(n) for n in self._weekdays.keys())):
            pass
        try:
            return self._weekdays[name.lower()]
        except KeyError:
            pass

    def month(self, name):
        if len(name) >= min((len(n) for n in self._months.keys())):
            pass
        try:
            return self._months[name.lower()] + 1
        except KeyError:
            pass

    def hms(self, name):
        try:
            return self._hms[name.lower()]
        except KeyError:
            return

    def ampm(self, name):
        try:
            return self._ampm[name.lower()]
        except KeyError:
            return

    def pertain(self, name):
        return name.lower() in self._pertain

    def utczone(self, name):
        return name.lower() in self._utczone

    def tzoffset(self, name):
        if name in self._utczone:
            return 0
        else:
            return self.TZOFFSET.get(name)

    def convertyear(self, year, century_specified=False):
        if year < 100:
            if not century_specified:
                year += self._century
                if abs(year - self._year) >= 50:
                    if year < self._year:
                        year += 100
                    else:
                        year -= 100
                    return year

    def validate(self, res):
        if res.year is not None:
            res.year = self.convertyear(res.year, res.century_specified)
        if res.tzoffset == 0 and not res.tzname or res.tzname == 'Z':
            res.tzname = 'UTC'
            res.tzoffset = 0
        else:
            if res.tzoffset != 0:
                if res.tzname:
                    if self.utczone(res.tzname):
                        res.tzoffset = 0
        return True


class _ymd(list):

    def __init__(self, tzstr, *args, **kwargs):
        super(self.__class__, self).__init__(*args, **kwargs)
        self.century_specified = False
        self.tzstr = tzstr

    @staticmethod
    def token_could_be_year(token, year):
        try:
            return int(token) == year
        except ValueError:
            return False

    @staticmethod
    def find_potential_year_tokens(year, tokens):
        return [token for token in tokens if _ymd.token_could_be_year(token, year)]

    def find_probable_year_index(self, tokens):
        """
        attempt to deduce if a pre 100 year was lost
         due to padded zeros being taken off
        """
        for index, token in enumerate(self):
            potential_year_tokens = _ymd.find_potential_year_tokens(token, tokens)
            if len(potential_year_tokens) == 1:
                if len(potential_year_tokens[0]) > 2:
                    return index

    def append(self, val):
        if hasattr(val, '__len__'):
            if val.isdigit():
                if len(val) > 2:
                    self.century_specified = True
                else:
                    if val > 100:
                        self.century_specified = True
                super(self.__class__, self).append(int(val))

    def resolve_ymd(self, mstridx, yearfirst, dayfirst):
        len_ymd = len(self)
        year, month, day = (None, None, None)
        if len_ymd > 3:
            raise ValueError('More than three YMD values')
        else:
            if len_ymd == 1 or mstridx != -1 and len_ymd == 2:
                if mstridx != -1:
                    month = self[mstridx]
                    del self[mstridx]
        if len_ymd > 1 or mstridx == -1:
            if self[0] > 31:
                year = self[0]
            else:
                day = self[0]
        else:
            if len_ymd == 2:
                if self[0] > 31:
                    year, month = self
                else:
                    if self[1] > 31:
                        month, year = self
                    else:
                        if dayfirst:
                            if self[1] <= 12:
                                day, month = self
                            month, day = self
            else:
                if len_ymd == 3:
                    pass
        if mstridx == 0:
            month, day, year = self
        else:
            if mstridx == 1:
                if self[0] > 31 or yearfirst and self[2] <= 31:
                    year, month, day = self
                else:
                    day, month, year = self
            else:
                if mstridx == 2:
                    if self[1] > 31:
                        day, year, month = self
                    else:
                        year, day, month = self
                else:
                    if self[0] > 31 or self.find_probable_year_index(_timelex.split(self.tzstr)) == 0 or yearfirst and self[1] <= 12 and self[2] <= 31:
                        if dayfirst:
                            if self[2] <= 12:
                                year, day, month = self
                            year, month, day = self
                    else:
                        if self[0] > 12 or dayfirst and self[1] <= 12:
                            day, month, year = self
                        else:
                            month, day, year = self
                        return (
                         year, month, day)


class parser(object):

    def __init__(self, info=None):
        self.info = info or parserinfo()

    def parse(self, timestr, default=None, ignoretz=False, tzinfos=None, **kwargs):
        """
        Parse the date/time string into a :class:`datetime.datetime` object.
        
        :param timestr:
            Any date/time string using the supported formats.
        
        :param default:
            The default datetime object, if this is a datetime object and not
            ``None``, elements specified in ``timestr`` replace elements in the
            default object.
        
        :param ignoretz:
            If set ``True``, time zones in parsed strings are ignored and a
            naive :class:`datetime.datetime` object is returned.
        
        :param tzinfos:
            Additional time zone names / aliases which may be present in the
            string. This argument maps time zone names (and optionally offsets
            from those time zones) to time zones. This parameter can be a
            dictionary with timezone aliases mapping time zone names to time
            zones or a function taking two parameters (``tzname`` and
            ``tzoffset``) and returning a time zone.
        
            The timezones to which the names are mapped can be an integer
            offset from UTC in minutes or a :class:`tzinfo` object.
        
            .. doctest::
               :options: +NORMALIZE_WHITESPACE
        
                >>> from dateutil.parser import parse
                >>> from dateutil.tz import gettz
                >>> tzinfos = {"BRST": -10800, "CST": gettz("America/Chicago")}
                >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
                datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -10800))
                >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
                datetime.datetime(2012, 1, 19, 17, 21,
                                  tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
        
            This parameter is ignored if ``ignoretz`` is set.
        
        :param **kwargs:
            Keyword arguments as passed to ``_parse()``.
        
        :return:
            Returns a :class:`datetime.datetime` object or, if the
            ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
            first element being a :class:`datetime.datetime` object, the second
            a tuple containing the fuzzy tokens.
        
        :raises ValueError:
            Raised for invalid or unknown string format, if the provided
            :class:`tzinfo` is not in a valid format, or if an invalid date
            would be created.
        
        :raises TypeError:
            Raised for non-string or character stream input.
        
        :raises OverflowError:
            Raised if the parsed date exceeds the largest valid C integer on
            your system.
        """
        if default is None:
            default = datetime.datetime.now().replace(hour=0, minute=0, second=0,
              microsecond=0)
        res, skipped_tokens = self._parse(timestr, **kwargs)
        if res is None:
            raise ValueError('Unknown string format')
        if len(res) == 0:
            raise ValueError('String does not contain a date.')
        repl = {}
        for attr in ('year', 'month', 'day', 'hour', 'minute', 'second', 'microsecond'):
            value = getattr(res, attr)
            if value is not None:
                repl[attr] = value

        if 'day' not in repl:
            cyear = default.year if res.year is None else res.year
            cmonth = default.month if res.month is None else res.month
            cday = default.day if res.day is None else res.day
            if cday > monthrange(cyear, cmonth)[1]:
                repl['day'] = monthrange(cyear, cmonth)[1]
        ret = default.replace(**repl)
        if res.weekday is not None:
            if not res.day:
                ret = ret + (relativedelta.relativedelta(weekday=res.weekday))
        if not ignoretz:
            if isinstance(tzinfos, collections.Callable) or tzinfos and res.tzname in tzinfos:
                if isinstance(tzinfos, collections.Callable):
                    tzdata = tzinfos(res.tzname, res.tzoffset)
                else:
                    tzdata = tzinfos.get(res.tzname)
                if isinstance(tzdata, datetime.tzinfo):
                    tzinfo = tzdata
                else:
                    if isinstance(tzdata, text_type):
                        tzinfo = tz.tzstr(tzdata)
                    else:
                        if isinstance(tzdata, integer_types):
                            tzinfo = tz.tzoffset(res.tzname, tzdata)
                        else:
                            raise ValueError('Offset must be tzinfo subclass, tz string, or int offset.')
                ret = ret.replace(tzinfo=tzinfo)
        if res.tzname:
            if res.tzname in time.tzname:
                ret = ret.replace(tzinfo=tz.tzlocal())
            if res.tzoffset == 0:
                ret = ret.replace(tzinfo=tz.tzutc())
            else:
                if res.tzoffset:
                    ret = ret.replace(tzinfo=tz.tzoffset(res.tzname, res.tzoffset))
            if kwargs.get('fuzzy_with_tokens', False):
                return (ret, skipped_tokens)
            return ret

    class _result(_resultbase):
        __slots__ = [
         'year', 'month', 'day', 'weekday',
         'hour', 'minute', 'second', 'microsecond',
         'tzname', 'tzoffset', 'ampm']

    def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False, fuzzy_with_tokens=False):
        """
        Private method which performs the heavy lifting of parsing, called from
        ``parse()``, which passes on its ``kwargs`` to this function.
        
        :param timestr:
            The string to parse.
        
        :param dayfirst:
            Whether to interpret the first value in an ambiguous 3-integer date
            (e.g. 01/05/09) as the day (``True``) or month (``False``). If
            ``yearfirst`` is set to ``True``, this distinguishes between YDM
            and YMD. If set to ``None``, this value is retrieved from the
            current :class:`parserinfo` object (which itself defaults to
            ``False``).
        
        :param yearfirst:
            Whether to interpret the first value in an ambiguous 3-integer date
            (e.g. 01/05/09) as the year. If ``True``, the first number is taken
            to be the year, otherwise the last number is taken to be the year.
            If this is set to ``None``, the value is retrieved from the current
            :class:`parserinfo` object (which itself defaults to ``False``).
        
        :param fuzzy:
            Whether to allow fuzzy parsing, allowing for string like "Today is
            January 1, 2047 at 8:21:00AM".
        
        :param fuzzy_with_tokens:
            If ``True``, ``fuzzy`` is automatically set to True, and the parser
            will return a tuple where the first element is the parsed
            :class:`datetime.datetime` datetimestamp and the second element is
            a tuple containing the portions of the string which were ignored:
        
            .. doctest::
        
                >>> from dateutil.parser import parse
                >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
                (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
        
        """
        if fuzzy_with_tokens:
            fuzzy = True
        info = self.info
        if dayfirst is None:
            dayfirst = info.dayfirst
        if yearfirst is None:
            yearfirst = info.yearfirst
        res = self._result()
        l = _timelex.split(timestr)
        last_skipped_token_i = -2
        skipped_tokens = list()
        try:
            ymd = _ymd(timestr)
            mstridx = -1
            len_l = len(l)
            i = 0
            while i < len_l:
                try:
                    value_repr = l[i]
                    value = float(value_repr)
                except ValueError:
                    value = None

                if value is not None:
                    len_li = len(l[i])
                    i += 1
                    if len(ymd) == 3:
                        if len_li in (2, 4):
                            if res.hour is None:
                                if i >= len_l or l[i] != ':' and info.hms(l[i]) is None:
                                    s = l[i - 1]
                                    res.hour = int(s[:2])
                                    if len_li == 4:
                                        res.minute = int(s[2:])
                                    elif len_li == 6 or len_li > 6 and l[i - 1].find('.') == 6:
                                        s = l[i - 1]
                                        if not ymd:
                                            if l[i - 1].find('.') == -1:
                                                ymd.append(s[:2])
                                                ymd.append(s[2:4])
                                                ymd.append(s[4:])
                                            res.hour = int(s[:2])
                                            res.minute = int(s[2:4])
                                            res.second, res.microsecond = _parsems(s[4:])
                                    elif len_li in (8, 12, 14):
                                        s = l[i - 1]
                                        ymd.append(s[:4])
                                        ymd.append(s[4:6])
                                        ymd.append(s[6:8])
                                        res.hour = len_li > 8 and int(s[8:10])
                                        res.minute = int(s[10:12])
                                        res.second = len_li > 12 and int(s[12:])
                                    elif i < len_l and info.hms(l[i]) is not None or i + 1 < len_l and l[i] == ' ' and info.hms(l[i + 1]) is not None:
                                        if l[i] == ' ':
                                            i += 1
                                        idx = info.hms(l[i])
                                        while idx == 0:
                                            res.hour = int(value)
                                            if value % 1:
                                                res.minute = int(60 * (value % 1))
                                            else:
                                                if idx == 1:
                                                    res.minute = int(value)
                                                    if value % 1:
                                                        res.second = int(60 * (value % 1))
                                                    else:
                                                        if idx == 2:
                                                            res.second, res.microsecond = _parsems(value_repr)
                                            i += 1
                                            if i >= len_l or idx == 2:
                                                break
                                                try:
                                                    value_repr = l[i]
                                                    value = float(value_repr)
                                                except ValueError:
                                                    break
                                                else:
                                                    i += 1
                                                    idx += 1
                                                    newidx = i < len_l and info.hms(l[i])
                                                    idx = newidx is not None and newidx

                                    elif i == len_l:
                                        if l[i - 2] == ' ':
                                            if info.hms(l[i - 3]) is not None:
                                                idx = info.hms(l[i - 3])
                                                if idx == 0:
                                                    res.minute = int(value)
                                                    sec_remainder = value % 1
                                                    if sec_remainder:
                                                        res.second = int(60 * sec_remainder)
                                                    else:
                                                        if idx == 1:
                                                            res.second, res.microsecond = _parsems(value_repr)
                                    elif i + 1 < len_l:
                                        if l[i] == ':':
                                            res.hour = int(value)
                                            i += 1
                                            value = float(l[i])
                                            res.minute = int(value)
                                            if value % 1:
                                                res.second = int(60 * (value % 1))
                                            i += 1
                                            res.second, res.microsecond = i < len_l and l[i] == ':' and _parsems(l[i + 1])
                                            i += 2
                                    elif i < len_l:
                                        if l[i] in ('-', '/', '.'):
                                            sep = l[i]
                                            ymd.append(value_repr)
                                            i += 1
                                            if i < len_l:
                                                pass
                                            if not info.jump(l[i]):
                                                try:
                                                    ymd.append(l[i])
                                                except ValueError:
                                                    value = info.month(l[i])
                                                    if value is not None:
                                                        ymd.append(value)
                                                        if not mstridx == -1:
                                                            raise AssertionError
                                                        mstridx = len(ymd) - 1
                                                    else:
                                                        return (None, None)

                                                i += 1
                                                if i < len_l:
                                                    if l[i] == sep:
                                                        i += 1
                                                        value = info.month(l[i])
                                                        if value is not None:
                                                            ymd.append(value)
                                                            mstridx = len(ymd) - 1
                                                            if not mstridx == -1:
                                                                raise AssertionError
                                                            else:
                                                                ymd.append(l[i])
                                            i += 1
                                    elif i >= len_l or info.jump(l[i]):
                                        if i + 1 < len_l:
                                            if info.ampm(l[i + 1]) is not None:
                                                res.hour = int(value)
                                                if res.hour < 12:
                                                    if info.ampm(l[i + 1]) == 1:
                                                        res.hour += 12
                                                    if res.hour == 12:
                                                        if info.ampm(l[i + 1]) == 0:
                                                            res.hour = 0
                                                i += 1
                                            ymd.append(value)
                                        i += 1
                                    elif info.ampm(l[i]) is not None:
                                        res.hour = int(value)
                                        if res.hour < 12:
                                            if info.ampm(l[i]) == 1:
                                                res.hour += 12
                                            if res.hour == 12:
                                                if info.ampm(l[i]) == 0:
                                                    res.hour = 0
                                        i += 1
                                    else:
                                        if not fuzzy:
                                            return (None, None)
                                        i += 1
                                    continue
                                    value = info.weekday(l[i])
                                    if value is not None:
                                        res.weekday = value
                                        i += 1
                                    continue
                                value = info.month(l[i])
                                if value is not None:
                                    ymd.append(value)
                                    if not mstridx == -1:
                                        raise AssertionError
                                    mstridx = len(ymd) - 1
                                    i += 1
                                    if i < len_l:
                                        if l[i] in ('-', '/'):
                                            sep = l[i]
                                            i += 1
                                            ymd.append(l[i])
                i += 1
                if i < len_l:
                    if l[i] == sep:
                        i += 1
                        ymd.append(l[i])
                        i += 1
                    else:
                        if i + 3 < len_l:
                            if l[i] == l[i + 2] == ' ':
                                if info.pertain(l[i + 1]):
                                    try:
                                        value = int(l[i + 3])
                                    except ValueError:
                                        pass
                                    else:
                                        ymd.append(str(info.convertyear(value)))

                                    i += 4
                            continue
                            value = info.ampm(l[i])
                            if value is not None:
                                val_is_ampm = True
                                if fuzzy:
                                    if res.ampm is not None:
                                        val_is_ampm = False
                                if res.hour is None:
                                    if fuzzy:
                                        val_is_ampm = False
                                    else:
                                        raise ValueError('No hour specified with ' + 'AM or PM flag.')
                                else:
                                    if not 0 <= res.hour <= 12:
                                        if fuzzy:
                                            val_is_ampm = False
                                        else:
                                            raise ValueError('Invalid hour specified for ' + '12-hour clock.')
                                        if val_is_ampm:
                                            if value == 1:
                                                if res.hour < 12:
                                                    res.hour += 12
                                                if value == 0:
                                                    if res.hour == 12:
                                                        res.hour = 0
                                            res.ampm = value
                                        else:
                                            if fuzzy:
                                                last_skipped_token_i = self._skip_token(skipped_tokens, last_skipped_token_i, i, l)
                                        i += 1
                                        continue
                                        if res.hour is not None:
                                            if len(l[i]) <= 5:
                                                if res.tzname is None:
                                                    pass
                            if res.tzoffset is None:
                                if not [x for x in l[i] if x not in string.ascii_uppercase]:
                                    res.tzname = l[i]
                                    res.tzoffset = info.tzoffset(res.tzname)
                                    i += 1
                                    if i < len_l:
                                        if l[i] in ('+', '-'):
                                            l[i] = ('+', '-')[l[i] == '+']
                                            res.tzoffset = None
                                            if info.utczone(res.tzname):
                                                res.tzname = None
                                                continue
                                signal = res.hour is not None and l[i] in ('+', '-') and (-1,
                                                                                          1)[l[i] == '+']
                                i += 1
                                len_li = len(l[i])
                                res.tzoffset = len_li == 4 and int(l[i][:2]) * 3600 + int(l[i][2:]) * 60
                            else:
                                if i + 1 < len_l:
                                    if l[i + 1] == ':':
                                        res.tzoffset = int(l[i]) * 3600 + int(l[i + 2]) * 60
                                        i += 2
                                    if len_li <= 2:
                                        res.tzoffset = int(l[i][:2]) * 3600
                                    else:
                                        return (None, None)
                                    i += 1
                                    res.tzoffset *= signal
                                    if i + 3 < len_l:
                                        if info.jump(l[i]):
                                            if l[i + 1] == '(':
                                                if l[i + 3] == ')':
                                                    pass
                                    if 3 <= len(l[i + 2]) <= 5:
                                        if not [x for x in l[i + 2] if x not in string.ascii_uppercase]:
                                            res.tzname = l[i + 2]
                                            i += 4
                                            continue
                                        if not (info.jump(l[i]) or fuzzy):
                                            return (None, None)
                            last_skipped_token_i = self._skip_token(skipped_tokens, last_skipped_token_i, i, l)
                            i += 1

            year, month, day = ymd.resolve_ymd(mstridx, yearfirst, dayfirst)
            if year is not None:
                res.year = year
                res.century_specified = ymd.century_specified
            if month is not None:
                res.month = month
            if day is not None:
                res.day = day
        except (IndexError, ValueError, AssertionError):
            return (None, None)

        if not info.validate(res):
            return (None, None)
        elif fuzzy_with_tokens:
            return (res, tuple(skipped_tokens))
        else:
            return (
             res, None)

    @staticmethod
    def _skip_token(skipped_tokens, last_skipped_token_i, i, l):
        if last_skipped_token_i == i - 1:
            skipped_tokens[(-1)] += l[i]
        else:
            skipped_tokens.append(l[i])
        last_skipped_token_i = i
        return last_skipped_token_i


DEFAULTPARSER = parser()

def parse(timestr, parserinfo=None, **kwargs):
    """
    
    Parse a string in one of the supported formats, using the
    ``parserinfo`` parameters.
    
    :param timestr:
        A string containing a date/time stamp.
    
    :param parserinfo:
        A :class:`parserinfo` object containing parameters for the parser.
        If ``None``, the default arguments to the :class:`parserinfo`
        constructor are used.
    
    The ``**kwargs`` parameter takes the following keyword arguments:
    
    :param default:
        The default datetime object, if this is a datetime object and not
        ``None``, elements specified in ``timestr`` replace elements in the
        default object.
    
    :param ignoretz:
        If set ``True``, time zones in parsed strings are ignored and a naive
        :class:`datetime` object is returned.
    
    :param tzinfos:
            Additional time zone names / aliases which may be present in the
            string. This argument maps time zone names (and optionally offsets
            from those time zones) to time zones. This parameter can be a
            dictionary with timezone aliases mapping time zone names to time
            zones or a function taking two parameters (``tzname`` and
            ``tzoffset``) and returning a time zone.
    
            The timezones to which the names are mapped can be an integer
            offset from UTC in minutes or a :class:`tzinfo` object.
    
            .. doctest::
               :options: +NORMALIZE_WHITESPACE
    
                >>> from dateutil.parser import parse
                >>> from dateutil.tz import gettz
                >>> tzinfos = {"BRST": -10800, "CST": gettz("America/Chicago")}
                >>> parse("2012-01-19 17:21:00 BRST", tzinfos=tzinfos)
                datetime.datetime(2012, 1, 19, 17, 21, tzinfo=tzoffset(u'BRST', -10800))
                >>> parse("2012-01-19 17:21:00 CST", tzinfos=tzinfos)
                datetime.datetime(2012, 1, 19, 17, 21,
                                  tzinfo=tzfile('/usr/share/zoneinfo/America/Chicago'))
    
            This parameter is ignored if ``ignoretz`` is set.
    
    :param dayfirst:
        Whether to interpret the first value in an ambiguous 3-integer date
        (e.g. 01/05/09) as the day (``True``) or month (``False``). If
        ``yearfirst`` is set to ``True``, this distinguishes between YDM and
        YMD. If set to ``None``, this value is retrieved from the current
        :class:`parserinfo` object (which itself defaults to ``False``).
    
    :param yearfirst:
        Whether to interpret the first value in an ambiguous 3-integer date
        (e.g. 01/05/09) as the year. If ``True``, the first number is taken to
        be the year, otherwise the last number is taken to be the year. If
        this is set to ``None``, the value is retrieved from the current
        :class:`parserinfo` object (which itself defaults to ``False``).
    
    :param fuzzy:
        Whether to allow fuzzy parsing, allowing for string like "Today is
        January 1, 2047 at 8:21:00AM".
    
    :param fuzzy_with_tokens:
        If ``True``, ``fuzzy`` is automatically set to True, and the parser
        will return a tuple where the first element is the parsed
        :class:`datetime.datetime` datetimestamp and the second element is
        a tuple containing the portions of the string which were ignored:
    
        .. doctest::
    
            >>> from dateutil.parser import parse
            >>> parse("Today is January 1, 2047 at 8:21:00AM", fuzzy_with_tokens=True)
            (datetime.datetime(2047, 1, 1, 8, 21), (u'Today is ', u' ', u'at '))
    
    :return:
        Returns a :class:`datetime.datetime` object or, if the
        ``fuzzy_with_tokens`` option is ``True``, returns a tuple, the
        first element being a :class:`datetime.datetime` object, the second
        a tuple containing the fuzzy tokens.
    
    :raises ValueError:
        Raised for invalid or unknown string format, if the provided
        :class:`tzinfo` is not in a valid format, or if an invalid date
        would be created.
    
    :raises OverflowError:
        Raised if the parsed date exceeds the largest valid C integer on
        your system.
    """
    if parserinfo:
        return parser(parserinfo).parse(timestr, **kwargs)
    else:
        return DEFAULTPARSER.parse(timestr, **kwargs)


class _tzparser(object):

    class _result(_resultbase):
        __slots__ = [
         'stdabbr', 'stdoffset', 'dstabbr', 'dstoffset',
         'start', 'end']

        class _attr(_resultbase):
            __slots__ = [
             'month', 'week', 'weekday',
             'yday', 'jyday', 'day', 'time']

        def __repr__(self):
            return self._repr('')

        def __init__(self):
            _resultbase.__init__(self)
            self.start = self._attr()
            self.end = self._attr()

    def parse(self, tzstr):
        res = self._result()
        l = _timelex.split(tzstr)
        try:
            len_l = len(l)
            i = 0
            while i < len_l:
                j = i
                while j < len_l:
                    if not [x for x in l[j] if x in '0123456789:,-+']:
                        j += 1

                if j != i:
                    if not res.stdabbr:
                        offattr = 'stdoffset'
                        res.stdabbr = ('').join(l[i:j])
                    else:
                        offattr = 'dstoffset'
                        res.dstabbr = ('').join(l[i:j])
                    i = j
                    if i < len_l and (l[i] in ('+', '-') or l[i][0] in '0123456789'):
                        if l[i] in ('+', '-'):
                            signal = (1, -1)[l[i] == '+']
                            i += 1
                        else:
                            signal = -1
                        len_li = len(l[i])
                        if len_li == 4:
                            setattr(res, offattr, (int(l[i][:2]) * 3600 + int(l[i][2:]) * 60) * signal)
                        else:
                            if i + 1 < len_l:
                                if l[i + 1] == ':':
                                    setattr(res, offattr, (int(l[i]) * 3600 + int(l[i + 2]) * 60) * signal)
                                    i += 2
                                if len_li <= 2:
                                    setattr(res, offattr, int(l[i][:2]) * 3600 * signal)
                                else:
                                    return
                                i += 1
                            if res.dstabbr:
                                break
                    else:
                        break

            if i < len_l:
                for j in range(i, len_l):
                    if l[j] == ';':
                        l[j] = ','

                if not l[i] == ',':
                    raise AssertionError
                i += 1
            if i >= len_l:
                pass
            else:
                if 8 <= l.count(',') <= 9:
                    pass
            if not [y for y in l[i:] if y not in '0123456789']:
                for x in (res.start, res.end):
                    x.month = int(l[i])
                    i += 2
                    if l[i] == '-':
                        value = int(l[i + 1]) * -1
                        i += 1
                    else:
                        value = int(l[i])
                    i += 2
                    if value:
                        x.week = value
                        x.weekday = (int(l[i]) - 1) % 7
                    else:
                        x.day = int(l[i])
                    i += 2
                    x.time = int(l[i])
                    i += 2

                if i < len_l:
                    if l[i] in ('-', '+'):
                        signal = (-1, 1)[l[i] == '+']
                        i += 1
                    else:
                        signal = 1
                    res.dstoffset = (res.stdoffset + int(l[i])) * signal
                else:
                    if l.count(',') == 2:
                        if l[i:].count('/') <= 2:
                            if not [y for y in l[i:] if y not in '0123456789']:
                                for x in (res.start, res.end):
                                    if l[i] == 'J':
                                        i += 1
                                        x.jyday = int(l[i])
                                    else:
                                        if l[i] == 'M':
                                            i += 1
                                            x.month = int(l[i])
                                            i += 1
                                            if not l[i] in ('-', '.'):
                                                raise AssertionError
                                            i += 1
                                            x.week = int(l[i])
                                            if x.week == 5:
                                                x.week = -1
                                            i += 1
                                            if not l[i] in ('-', '.'):
                                                raise AssertionError
                                            i += 1
                                            x.weekday = (int(l[i]) - 1) % 7
                                        else:
                                            x.yday = int(l[i]) + 1
                                        i += 1
                                        if i < len_l:
                                            if l[i] == '/':
                                                i += 1
                                                len_li = len(l[i])
                                                if len_li == 4:
                                                    x.time = int(l[i][:2]) * 3600 + int(l[i][2:]) * 60
                                    if i + 1 < len_l:
                                        if l[i + 1] == ':':
                                            x.time = int(l[i]) * 3600 + int(l[i + 2]) * 60
                                            i += 2
                                            if i + 1 < len_l:
                                                if l[i + 1] == ':':
                                                    i += 2
                                                    x.time += int(l[i])
                                                if len_li <= 2:
                                                    x.time = int(l[i][:2]) * 3600
                                                else:
                                                    return
                                                i += 1
                                        if not i == len_l:
                                            if not l[i] == ',':
                                                raise AssertionError
                                        i += 1

                                if not i >= len_l:
                                    raise AssertionError
        except (IndexError, ValueError, AssertionError):
            return

        return res


DEFAULTTZPARSER = _tzparser()

def _parsetz(tzstr):
    return DEFAULTTZPARSER.parse(tzstr)


def _parsems(value):
    """Parse a I[.F] seconds value into (seconds, microseconds)."""
    if '.' not in value:
        return (int(value), 0)
    else:
        i, f = value.split('.')
        return (
         int(i), int(f.ljust(6, '0')[:6]))